package com.sws.person.service.impl;

import com.sws.common.utils.SecurityUtils;
import com.sws.common.utils.access_tokenutil.util.AccessTokenUtil;
import com.sws.common.utils.PidGeneratorUtil;
import com.sws.device.domain.DevDevice;
import com.sws.device.service.DeviceIpResolverService;
import com.sws.device.service.IDevDeviceService;
import com.sws.person.ball.CameraServerProperties;
import com.sws.person.ball.CameraServerService;
import com.sws.person.domain.PerPerson;
import com.sws.person.exception.DeviceIdMissingException;
import com.sws.person.mapper.PerPersonMapper;
import com.sws.person.service.IPerPersonService;
import com.sws.rel.domain.PersonDeviceRel;
import com.sws.rel.service.IPersonDeviceRelService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 人员信息Service业务层处理
 *
 * @author cx
 * @date 2025-06-09
 */

@Service
public class PerPersonServiceImpl implements IPerPersonService {
    private static final Logger log = LoggerFactory.getLogger(PerPersonServiceImpl.class);
    @Autowired
    private PerPersonMapper perPersonMapper;
    @Autowired
    private CameraServerProperties cameraServerProperties; // 注入配置
    @Autowired
    private RestTemplate restTemplate; // 注入配置好的RestTemplate
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private DeviceIpResolverService deviceIpResolverService;
    @Autowired
    private CameraServerService cameraServerService;
    @Autowired
    private IDevDeviceService devDeviceService;

    @Autowired
    private IPersonDeviceRelService personDeviceRelService;

    // 方式2：或使用RedisUtil（需确保已注入）

    /**
     * 查询人员信息
     *
     * @param id 人员信息主键
     * @return 人员信息
     */
    @Override
    public PerPerson selectPerPersonById(Long id) {
        return perPersonMapper.selectPerPersonById(id);
    }

    /**
     * 查询人员信息列表
     *
     * @param perPerson 人员信息
     * @return 人员信息
     */
    @Override
    public List<PerPerson> selectPerPersonList(PerPerson perPerson) {
        return perPersonMapper.selectPerPersonList(perPerson);
    }

    /**
     * 新增人员信息
     *
     * @param perPerson 人员信息
     * @return 结果
     */
    @Override
    public int insertPerPerson(PerPerson perPerson) {
        perPerson.setCreateBy(SecurityUtils.getUsername());
        perPerson.setCreateTime(new Date());
        perPerson.setDelFlag(0);
        return perPersonMapper.insertPerPerson(perPerson);
    }


    /**
     * 添加人员信息到多个设备
     *
     * @param perPerson 人员信息（包含多个deviceIds）
     * @return 处理后的人员信息
     */
    public PerPerson addPersontoCamera(PerPerson perPerson) throws Exception {
        if (perPerson == null || perPerson.getDeviceIds() == null || perPerson.getDeviceIds().isEmpty()) {
            throw new ServiceException("人员信息或设备ID列表不能为空");
        }

        log.info("开始向多个设备({})添加人员", perPerson.getDeviceIds().size());
        
        // 如果没有提供PID，则生成随机PID
        if (perPerson.getPid() == null || perPerson.getPid().isEmpty()) {
            String randomPid = PidGeneratorUtil.generatePid();
            perPerson.setPid(randomPid);
            log.info("为新人员生成随机PID: {}", randomPid);
        }
        
        // 处理照片 - 只需要处理一次
        String base64Photo = processPhoto(perPerson);
        if (base64Photo == null) {
            throw new ServiceException("图片处理失败");
        }
        
        PerPerson resultPerson = null;
        boolean anySuccess = false;
        StringBuilder errors = new StringBuilder();
        
        // 遍历所有设备ID
        for (String deviceSn : perPerson.getDeviceIds()) {
            try {
                // 1. 检查关联关系是否已存在
                boolean relationExists = !personDeviceRelService.checkPersonDeviceRelNotExists(perPerson.getPid(), deviceSn);
                
                if (relationExists) {
                    log.info("人员 {} 与设备 {} 的关联关系已存在，跳过该设备", perPerson.getPid(), deviceSn);
                    continue; // 跳过已存在关联的设备
                }
                
                // 2. 在设备上创建人员
                PerPerson devicePerson = addPersontoSingleCamera(perPerson, deviceSn, base64Photo);
                
                // 3. 创建成功，添加关联记录
                if (devicePerson != null) {
                    anySuccess = true;
                    
                    // 创建设备关联
                    PersonDeviceRel newRel = new PersonDeviceRel();
                    newRel.setPersonPid(perPerson.getPid());
                    newRel.setDeviceSn(deviceSn);
                    newRel.setSyncStatus(0L); // 已同步状态
                    personDeviceRelService.insertPersonDeviceRel(newRel);
                    
                    log.info("成功添加人员 {} 到设备 {} 并创建关联关系", perPerson.getPid(), deviceSn);
                    
                    // 保存第一个成功设备的照片路径作为返回结果
                    if (resultPerson == null) {
                        resultPerson = devicePerson;
                    }
                }
            } catch (Exception e) {
                log.error("添加人员到设备 {} 失败: {}", deviceSn, e.getMessage());
                errors.append("设备 ").append(deviceSn).append(" 添加失败: ").append(e.getMessage()).append("; ");
            }
        }
        
        // 检查是否至少有一个设备添加成功
        if (!anySuccess) {
            throw new ServiceException("所有设备添加失败: " + errors.toString());
        }
        
        // 设置多设备ID列表到返回对象
        resultPerson.setDeviceIds(perPerson.getDeviceIds());
        
        // 设置第一个设备ID作为主设备ID
        perPerson.setDeviceId(perPerson.getDeviceIds().get(0));
        
        return resultPerson;
    }

    /**
     * 处理人员照片，转换为Base64
     */
    private String processPhoto(PerPerson perPerson) {
        String photoPath = perPerson.getPhoto();
        if (photoPath == null || photoPath.isEmpty()) {
            throw new ServiceException("人员照片路径不能为空");
        }
        
        // 将图片转换为Base64
        String base64Photo = null;
        try {
            if (photoPath.startsWith("http") || photoPath.startsWith("https")) {
                // 网络路径
                base64Photo = downloadImageAsBase64(photoPath, perPerson.getDeviceIds().get(0));
            } else {
                // 本地路径
                String pre = "D:/ruoyi-picture";
                base64Photo = convertImageToBase64(pre + photoPath);
            }
        } catch (Exception e) {
            log.error("处理照片失败: {}", e.getMessage());
            throw new ServiceException("照片处理失败: " + e.getMessage());
        }
        
        return base64Photo;
    }

    /**
     * 添加人员到单个摄像头
     */
    private PerPerson addPersontoSingleCamera(PerPerson perPerson, String deviceSn, String base64Photo) throws Exception {
        // 1. 调用摄像头服务器的 API
        String url = cameraServerProperties.getBaseUrlBySn(deviceSn) + "/cgi-bin/jvsweb.cgi?cmd=";
        
        HttpHeaders headers = new HttpHeaders();
        
        // 获取设备Token
        String accessToken = AccessTokenUtil.getTokenBySn(deviceSn, deviceIpResolverService);
        if (accessToken == null || accessToken.isEmpty()) {
            throw new ServiceException("无法获取设备 " + deviceSn + " 的访问令牌");
        }
        headers.set("Cookie", "language=zh; username=admin; Access-Token=" + accessToken);
        
        // 构建参数Map
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("pid", perPerson.getPid());
        paramMap.put("name", perPerson.getName() != null ? perPerson.getName() : "");
        paramMap.put("work_id", perPerson.getWorkId() != null ? perPerson.getWorkId() : "");
        paramMap.put("id_card_no", perPerson.getIdCardNo() != null ? perPerson.getIdCardNo() : "");
        paramMap.put("ic_card_no", perPerson.getIcCardNo() != null ? perPerson.getIcCardNo() : "");
        paramMap.put("gender", perPerson.getGender() != null ? perPerson.getGender() : 0);
        paramMap.put("age", perPerson.getAge() != null ? perPerson.getAge() : 0);
        paramMap.put("department", perPerson.getDepartment() != null ? perPerson.getDepartment() : "");
        paramMap.put("photo", base64Photo);
        paramMap.put("category", perPerson.getCategory() != null ? perPerson.getCategory() : 4);
        paramMap.put("phone", perPerson.getPhone() != null ? perPerson.getPhone() : "");
        
        // 构造请求体
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("uri", "/person/add");
        requestBody.put("param", paramMap);
        
        log.info("向设备 {} 发送添加人员请求: PID={}", deviceSn, perPerson.getPid());
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<Map> response = restTemplate.postForEntity(url, requestEntity, Map.class);
        
        if (response.getStatusCode().is2xxSuccessful()) {
            Map<String, Object> responseBody = response.getBody();
            if (responseBody != null && "0".equals(responseBody.get("code").toString())) {
                Map<String, Object> result = (Map<String, Object>) responseBody.get("result");
                String pid = (String) result.get("pid");
                if (pid == null || pid.isEmpty()) {
                    throw new ServiceException("设备返回的PID为空");
                }
                
                PerPerson person_photo = selectCameraPersonByPid(pid, deviceSn);
                if (person_photo == null) {
                    throw new ServiceException("获取设备返回的人员照片信息失败");
                }
                
                String photo = person_photo.getPhoto();
                if (photo == null || photo.isEmpty()) {
                    throw new ServiceException("设备返回的照片路径为空");
                }
                
                // 修改照片路径，添加设备SN信息
                String modifiedPhoto = addDeviceSnToPhotoPath(photo, deviceSn);
                
                // 构造返回结果
                PerPerson resultPerson = new PerPerson();
                resultPerson.setPid(perPerson.getPid());
                resultPerson.setPhoto(modifiedPhoto);
                resultPerson.setDeviceId(deviceSn);
                
                return resultPerson;
            } else {
                String msg = responseBody.get("msg") != null ? responseBody.get("msg").toString() : "未知错误";
                
                // 处理"uuid already exists"错误 - 表示人员在设备上已存在
                if (msg.contains("uuid already exists")) {
                    log.info("设备 {} 上已存在人员 {}，尝试查询现有人员信息", deviceSn, perPerson.getPid());
                    
                    // 检查人员-设备关联关系是否存在
                    boolean relationExists = !personDeviceRelService.checkPersonDeviceRelNotExists(perPerson.getPid(), deviceSn);
                    
                    // 如果关联关系不存在，则创建关联关系
                    if (!relationExists) {
                        log.info("人员 {} 与设备 {} 的关联关系不存在，创建新关联", perPerson.getPid(), deviceSn);
                        PersonDeviceRel newRel = new PersonDeviceRel();
                        newRel.setPersonPid(perPerson.getPid());
                        newRel.setDeviceSn(deviceSn);
                        newRel.setSyncStatus(0L); // 已同步状态
                        personDeviceRelService.insertPersonDeviceRel(newRel);
                    }
                    
                    // 获取设备上现有的人员照片信息
                    try {
                        PerPerson existingPerson = selectCameraPersonByPid(perPerson.getPid(), deviceSn);
                        if (existingPerson != null && existingPerson.getPhoto() != null) {
                            // 修改照片路径，添加设备SN信息
                            String modifiedPhoto = addDeviceSnToPhotoPath(existingPerson.getPhoto(), deviceSn);
                            
                            // 构造返回结果
                            PerPerson resultPerson = new PerPerson();
                            resultPerson.setPid(perPerson.getPid());
                            resultPerson.setPhoto(modifiedPhoto);
                            resultPerson.setDeviceId(deviceSn);
                            
                            log.info("成功获取设备 {} 上已存在人员 {} 的信息", deviceSn, perPerson.getPid());
                            return resultPerson;
                        }
                    } catch (Exception e) {
                        log.warn("尝试获取设备 {} 上已存在人员 {} 的信息失败: {}", deviceSn, perPerson.getPid(), e.getMessage());
                    }
                    
                    // 如果无法获取现有信息，则构造一个基本的返回对象
                    PerPerson resultPerson = new PerPerson();
                    resultPerson.setPid(perPerson.getPid());
                    // 使用传入的照片路径
                    resultPerson.setPhoto(perPerson.getPhoto() != null ? 
                        addDeviceSnToPhotoPath(perPerson.getPhoto(), deviceSn) : null);
                    resultPerson.setDeviceId(deviceSn);
                    
                    log.info("已处理设备 {} 上的UUID已存在情况，返回基本信息", deviceSn);
                    return resultPerson;
                }
                
                throw new ServiceException("设备 " + deviceSn + " 返回错误: " + msg);
            }
        }
        throw new ServiceException("请求设备 " + deviceSn + " 失败: HTTP " + response.getStatusCodeValue());
    }

    /**
     * 在照片路径中添加设备SN信息
     * 将原始路径修改为包含设备SN的格式
     */
    private String addDeviceSnToPhotoPath(String originalPath, String deviceSn) {
        if (originalPath == null || originalPath.isEmpty()) {
            return originalPath;
        }
        
        // 检查路径是否已经包含设备SN信息
        if (originalPath.contains("/device/" + deviceSn + "/")) {
            return originalPath; // 已经包含设备信息，不需要修改
        }
        
        // 假设原始路径格式为 /images/xxx.jpg
        if (originalPath.startsWith("/")) {
            return "/device/" + deviceSn + originalPath;
        } else {
            return "/device/" + deviceSn + "/" + originalPath;
        }
    }

    //TODO   更改cameraServerProperties.getBaseUrl()
    public PerPerson selectCameraPersonByPid(String pid, String sn) throws Exception {
        if (pid == null || pid.isEmpty()) {
            throw new ServiceException("PID不能为空");
        }

        // 1. 调用摄像头服务器的 API
        String url = cameraServerProperties.getBaseUrlBySn(sn) + "/cgi-bin/jvsweb.cgi?cmd=";

        HttpHeaders headers = new HttpHeaders();
        String accessToken = null;
        accessToken = AccessTokenUtil.getTokenBySn(sn, deviceIpResolverService);
        if(accessToken == null){
            throw new DeviceIdMissingException("设备序列号没有正确传达");
              }

        if (accessToken == null || accessToken.isEmpty()) {
            throw new ServiceException("获取设备Token失败");
        }
        headers.set("Cookie", "language=zh; username=admin; Access-Token=" + accessToken);

        // 构造请求体
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("uri", "/person/query");
        requestBody.put("param", Collections.singletonMap("pid", pid));

        System.out.println("根据pid:" + pid + ",向设备发送根据pid查询请求：" + requestBody);
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<Map> response = restTemplate.postForEntity(url, requestEntity, Map.class);

        if (response.getStatusCode().is2xxSuccessful()) {
            Map<String, Object> responseBody = response.getBody();
            System.out.println("接收到响应：" + responseBody);
            if (responseBody != null && "0".equals(responseBody.get("code").toString())) {
                Map<String, Object> result = (Map<String, Object>) responseBody.get("result");
                String photo_url = (String) result.get("photo");
                //构造响应体
                PerPerson person = new PerPerson();
                person.setPhoto(photo_url);
                return person;
            } else {
                throw new Exception("设备返回错误");
            }
        } else {
            throw new Exception("请求错误");
        }

    }

    /**
     * 将图片文件转换为Base64编码
     * @param imagePath 图片文件路径
     * @return Base64编码的字符串
     * @throws IOException 如果文件读取失败
     */
//    private String convertImageToBase64(String imagePath) throws IOException {
//        File file = new File(imagePath);
//        if (!file.exists()) {
//            throw new IOException("文件不存在: " + imagePath);
//        }
//
//        byte[] imageBytes = Files.readAllBytes(file.toPath());
//        String base64 = Base64.getEncoder().encodeToString(imageBytes);
//        System.out.println("成功读取文件并转换为base64，文件大小: {} bytes"+imageBytes.length);
//        return base64;
//    }

    /**
     * 修改人员信息 - 同时更新本地和设备服务器
     *
     * @param perPerson 人员信息
     * @return 结果
     */
    @Override
    @Transactional
    public int updatePerPerson(PerPerson perPerson) {
        try {
            // 1. 获取当前人员已关联的设备
            List<String> existingDeviceSns = personDeviceRelService.getDeviceSnsByPersonPid(perPerson.getPid());
            Set<String> existingDeviceSet = new HashSet<>(existingDeviceSns);
            Set<String> newDeviceSet = new HashSet<>(perPerson.getDeviceIds());
            
            // 2. 计算需要新增和删除的设备关联
            Set<String> devicesToAdd = new HashSet<>(newDeviceSet);
            devicesToAdd.removeAll(existingDeviceSet); // 新设备集合减去已存在设备集合 = 需要添加的设备
            
            Set<String> devicesToRemove = new HashSet<>(existingDeviceSet);
            devicesToRemove.removeAll(newDeviceSet); // 已存在设备集合减去新设备集合 = 需要删除的设备
            
            // 3. 对需要继续保留的设备进行更新
            Set<String> devicesToUpdate = new HashSet<>(newDeviceSet);
            devicesToUpdate.retainAll(existingDeviceSet); // 两个集合的交集 = 需要更新的设备

            // 获取第一张照片用于处理
            String base64Photo = null;
            if (perPerson.getPhoto() != null && 
               !perPerson.getPhoto().equals(perPersonMapper.selectPerPersonById(perPerson.getId()).getPhoto())) {
                // 照片被修改，需要重新处理
                base64Photo = processPhoto(perPerson);
            }
            
            // 4. 处理需要添加的设备
            for (String deviceSn : devicesToAdd) {
                try {
                    // 在设备上创建人员
                    if (base64Photo != null) {
                        addPersontoSingleCamera(perPerson, deviceSn, base64Photo);
                    } else {
                        // 如果没有新照片，则使用原始照片添加到新设备
                        PerPerson originalPerson = perPersonMapper.selectPerPersonById(perPerson.getId());
                        String photoPath = originalPerson.getPhoto();
                        String originalBase64 = processPhotoWithPath(photoPath, deviceSn);
                        addPersontoSingleCamera(perPerson, deviceSn, originalBase64);
                    }
                    
                    // 创建设备关联记录
                    PersonDeviceRel newRel = new PersonDeviceRel();
                    newRel.setPersonPid(perPerson.getPid());
                    newRel.setDeviceSn(deviceSn);
                    newRel.setSyncStatus(0L);
                    personDeviceRelService.insertPersonDeviceRel(newRel);
                    
                    log.info("为人员 {} 添加设备 {} 关联", perPerson.getPid(), deviceSn);
                } catch (Exception e) {
                    log.error("向设备 {} 添加人员 {} 失败: {}", deviceSn, perPerson.getPid(), e.getMessage());
                }
            }
            
            // 5. 处理需要更新的设备
            for (String deviceSn : devicesToUpdate) {
                try {
                    // 更新设备上的人员信息
                    perPerson.setDeviceId(deviceSn);
                    updatePersonInCamera(perPerson);
                    log.info("在设备 {} 上更新人员 {} 信息", deviceSn, perPerson.getPid());
                } catch (Exception e) {
                    log.error("在设备 {} 上更新人员 {} 失败: {}", deviceSn, perPerson.getPid(), e.getMessage());
                }
            }
            
            // 6. 处理需要删除的设备关联
            for (String deviceSn : devicesToRemove) {
                try {
                    // 从设备上删除人员
                    deletePersonFromCamera(perPerson.getPid(), deviceSn);
                    
                    // 删除关联记录（使用物理删除替代标记删除）
                    personDeviceRelService.deletePersonDeviceRelByPersonIdAndDeviceSn(perPerson.getPid(), deviceSn);
                    
                    log.info("删除人员 {} 与设备 {} 的关联", perPerson.getPid(), deviceSn);
                } catch (Exception e) {
                    log.error("删除人员 {} 与设备 {} 的关联失败: {}", perPerson.getPid(), deviceSn, e.getMessage());
                }
            }
            
            // 7. 更新本地数据库
            perPerson.setDeviceId(perPerson.getDeviceIds().get(0)); // 设置第一个设备为主设备
            perPerson.setUpdateBy(SecurityUtils.getUsername());
            perPerson.setUpdateTime(new Date());
            return perPersonMapper.updatePerPerson(perPerson);
        } catch (Exception e) {
            throw new ServiceException("更新人员信息失败: " + e.getMessage());
        }
    }

    /**
     * 根据路径处理照片
     */
    private String processPhotoWithPath(String photoPath, String deviceSn) {
        if (photoPath == null || photoPath.isEmpty()) {
            throw new ServiceException("人员照片路径不能为空");
        }
        
        String base64Photo = null;
        try {
            if (photoPath.startsWith("http") || photoPath.startsWith("https")) {
                base64Photo = downloadImageAsBase64(photoPath, deviceSn);
            } else {
                String pre = "D:/ruoyi-picture";
                base64Photo = convertImageToBase64(pre + photoPath);
            }
        } catch (Exception e) {
            log.error("处理照片失败: {}", e.getMessage());
            throw new ServiceException("照片处理失败: " + e.getMessage());
        }
        
        return base64Photo;
    }

    /**
     * 更新设备上的人员信息 - 修复图片未修改时图片被清空的问题
     */
    public void updatePersonInCamera(PerPerson perPerson) throws Exception {
        // 1. 查询数据库获取原始人员信息
        PerPerson originalPerson = perPersonMapper.selectPerPersonByPid(perPerson.getPid());
        if (originalPerson == null) {
            throw new ServiceException("未找到原始人员记录");
        }

        // 2. 调用摄像头 API
        String deviceSn = perPerson.getDeviceId();
        String url = cameraServerProperties.getBaseUrlBySn(deviceSn) + "/cgi-bin/jvsweb.cgi?cmd=";
        HttpHeaders headers = new HttpHeaders();
        // 使用deviceIpResolverService通过设备SN获取设备的AccessToken
        String accessToken = AccessTokenUtil.getTokenBySn(deviceSn, deviceIpResolverService);
        headers.set("Cookie", "language=zh; username=admin; Access-Token=" + accessToken);

        // 3. 构造请求体
        Map<String, Object> paramMap = new HashMap<>();


        paramMap.put("pid", perPerson.getPid());
        paramMap.put("name", perPerson.getName() != null ? perPerson.getName() : "");
        paramMap.put("work_id", perPerson.getWorkId() != null ? perPerson.getWorkId() : "");
        paramMap.put("id_card_no", perPerson.getIdCardNo() != null ? perPerson.getIdCardNo() : "");
        paramMap.put("ic_card_no", perPerson.getIcCardNo() != null ? perPerson.getIcCardNo() : "");
        paramMap.put("gender", perPerson.getGender() != null ? perPerson.getGender() : 0);
        paramMap.put("age", perPerson.getAge() != null ? perPerson.getAge() : 0);
        paramMap.put("department", perPerson.getDepartment() != null ? perPerson.getDepartment() : "");
        paramMap.put("category", perPerson.getCategory() != null ? perPerson.getCategory() : 4);
        paramMap.put("phone", perPerson.getPhone() != null ? perPerson.getPhone() : "");

        // 4. 图片处理逻辑 - 修复点
        String photoPath = perPerson.getPhoto();
        String originalPhotoPath = originalPerson.getPhoto();
        String base64Image = null;

        // 情况1: 用户修改了图片
        if (photoPath != null && !Objects.equals(photoPath, originalPhotoPath)) {
            if (!photoPath.startsWith("http") && !photoPath.startsWith("https")) {
                // 本地图片转换为Base64
                String pre = "D:/ruoyi-picture";
                base64Image = convertImageToBase64(pre + photoPath);
            } else {
                // 网络图片下载后转换为Base64
                base64Image = downloadImageAsBase64(photoPath, perPerson.getDeviceId());
            }
            // 更新Redis缓存
            if (base64Image != null) {
                redisTemplate.opsForValue().set("person:photo:" + perPerson.getPid(), base64Image, 24, TimeUnit.HOURS);
            }
        }
        // 情况2: 用户未修改图片
        else {
            // 尝试从Redis获取缓存
            base64Image = redisTemplate.opsForValue().get("person:photo:" + perPerson.getPid());

            // 缓存不存在，从原始图片获取
            if (base64Image == null) {
                // 判断原始图片类型
                if (originalPhotoPath != null && !originalPhotoPath.startsWith("http") && !originalPhotoPath.startsWith("https")) {
                    // 本地图片
                    String pre = "D:/ruoyi-picture";
                    base64Image = convertImageToBase64(pre + originalPhotoPath);
                } else {
                    // 网络图片
                    base64Image = downloadImageAsBase64(originalPhotoPath, perPerson.getDeviceId());
                }

                // 存入Redis缓存
                if (base64Image != null) {
                    redisTemplate.opsForValue().set("person:photo:" + perPerson.getPid(), base64Image, 24, TimeUnit.HOURS);
                }
            }
        }

        // 确保有有效的Base64图片
        if (base64Image != null) {
            paramMap.put("photo", base64Image);
        } else {
            log.warn("无法获取图片Base64编码，PID: {}", perPerson.getPid());
            // 没有图片时的处理逻辑 - 根据设备要求可能需要特殊处理
            // paramMap.put("photo", ""); // 如果设备要求必须提供图片字段
        }

        // 5. 发送请求
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("uri", "/person/update");
        requestBody.put("param", paramMap);

        log.info("向设备发送修改人员请求: PID={}", perPerson.getPid());
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<Map> response = restTemplate.postForEntity(url, requestEntity, Map.class);

        // 6. 处理响应
        if (response.getStatusCode().is2xxSuccessful()) {
            Map<String, Object> responseBody = response.getBody();
            if (responseBody != null && "0".equals(String.valueOf(responseBody.get("code")))) {
                Map<String, Object> result = (Map<String, Object>) responseBody.get("result");
                String pid = (String) result.get("pid");
                PerPerson updatedPerson = selectCameraPersonByPid(pid, perPerson.getDeviceId());
                if (updatedPerson.getPhoto() != null) {
                    // 修改照片路径，添加设备SN信息
                    String modifiedPhoto = addDeviceSnToPhotoPath(updatedPerson.getPhoto(), perPerson.getDeviceId());
                    perPerson.setPhoto(modifiedPhoto);
                }
            } else {
                log.error("设备返回错误: {}", responseBody);
            }
        } else {
            log.error("设备请求失败: HTTP {}", response.getStatusCodeValue());
        }
    }

    /**
     * 下载图片并转换为Base64编码
     */
    private String downloadImageAsBase64(String imageUrl, String sn) {
        try {
            if (imageUrl == null || imageUrl.isEmpty()) {
                log.warn("图片URL为空");
                return null;
            }

            // 确保URL格式正确
            String fullUrl = imageUrl.startsWith("http") ? imageUrl : cameraServerProperties.getBaseUrlBySn(sn) + "/" + imageUrl;

            ResponseEntity<byte[]> response = restTemplate.getForEntity(fullUrl, byte[].class);
            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                return Base64.getEncoder().encodeToString(response.getBody());
            } else {
                log.error("下载图片失败: HTTP {} - URL: {}", response.getStatusCodeValue(), fullUrl);
            }
        } catch (Exception e) {
            log.error("下载图片失败: {}", imageUrl, e);
        }
        return null;
    }

    /**
     * 将图片文件转换为Base64编码 - 添加日志和错误处理
     */
    private String convertImageToBase64(String imagePath) {
        try {
            if (imagePath == null || imagePath.isEmpty()) {
                log.warn("图片路径为空");
                return null;
            }

            File file = new File(imagePath);
            if (!file.exists()) {
                log.error("图片文件不存在: {}", imagePath);
                return null;
            }

            byte[] imageBytes = Files.readAllBytes(file.toPath());
            String base64 = Base64.getEncoder().encodeToString(imageBytes);
            log.info("成功转换图片为Base64: {}, 大小: {} bytes", imagePath, imageBytes.length);
            return base64;
        } catch (IOException e) {
            log.error("图片转换Base64失败: {}", imagePath, e);
            return null;
        }
    }

    /**
     * 批量删除人员信息 - 增强版：删除所有设备上的人员信息及关联关系
     */
    @Override
    @Transactional
    public int deletePerPersonByIds(Long[] ids) {
        int count = 0;
        for (Long id : ids) {
            PerPerson person = perPersonMapper.selectPerPersonById(id);
            if (person != null) {
                // 获取此人员关联的所有设备
                List<String> deviceSns = personDeviceRelService.getDeviceSnsByPersonPid(person.getPid());
                boolean allDevicesSuccess = true;
                
                // 遍历所有设备，删除设备上的人员信息
                for (String deviceSn : deviceSns) {
                    boolean deleted = deletePersonFromCamera(person.getPid(), deviceSn);
                    if (!deleted) {
                        log.warn("从设备 {} 删除人员 {} 失败", deviceSn, person.getPid());
                        allDevicesSuccess = false;
                    } else {
                        log.info("从设备 {} 删除人员 {} 成功", deviceSn, person.getPid());
                    }
                }
                
                // 删除所有设备关联关系
                int relDeleted = personDeviceRelService.deleteAllRelationsByPersonPid(person.getPid());
                log.info("删除人员 {} 的 {} 个设备关联关系", person.getPid(), relDeleted);
                
                // 标记本地人员记录为删除
                person.setDelFlag(1);
                person.setUpdateBy(SecurityUtils.getUsername());
                person.setUpdateTime(new Date());
                count += perPersonMapper.updatePerPerson(person);
                
                if (!allDevicesSuccess) {
                    log.warn("人员 {} 的部分设备数据删除失败，但数据库记录已标记为删除", person.getPid());
                }
            }
        }
        return count;
    }

    /**
     * 删除人员信息 - 增强版：删除所有设备上的人员信息及关联关系
     */
    @Override
    @Transactional
    public int deletePerPersonById(Long id) {
        PerPerson person = perPersonMapper.selectPerPersonById(id);
        if (person == null) {
            return 0;
        }

        // 获取此人员关联的所有设备
        List<String> deviceSns = personDeviceRelService.getDeviceSnsByPersonPid(person.getPid());
        boolean allDevicesSuccess = true;
        
        // 遍历所有设备，删除设备上的人员信息
        for (String deviceSn : deviceSns) {
            boolean deleted = deletePersonFromCamera(person.getPid(), deviceSn);
            if (!deleted) {
                log.warn("从设备 {} 删除人员 {} 失败", deviceSn, person.getPid());
                allDevicesSuccess = false;
            } else {
                log.info("从设备 {} 删除人员 {} 成功", deviceSn, person.getPid());
            }
        }
        
        // 删除所有设备关联关系
        int relDeleted = personDeviceRelService.deleteAllRelationsByPersonPid(person.getPid());
        log.info("删除人员 {} 的 {} 个设备关联关系", person.getPid(), relDeleted);
        
        // 标记本地人员记录为删除
        person.setDelFlag(1);
        person.setUpdateBy(SecurityUtils.getUsername());
        person.setUpdateTime(new Date());
        int result = perPersonMapper.updatePerPerson(person);
        
        if (!allDevicesSuccess) {
            log.warn("人员 {} 的部分设备数据删除失败，但数据库记录已标记为删除", person.getPid());
        }
        
        return result;
    }

    @Override
    @Transactional
    public int syncPersonsFromCamera(List<Map<String, Object>> personList, String sn) {
        // 收集所有要同步的pid
        Set<String> pids = new HashSet<>();
        for (Map<String, Object> personData : personList) {
            pids.add(personData.get("pid").toString());
        }

        // 删除不在同步列表中的记录
        if (!pids.isEmpty()) {
            perPersonMapper.deletePersonsNotInPids(pids);
        }

        // 处理每条记录
        int successCount = 0;
        for (Map<String, Object> personData : personList) {
            // 将设备SN传递给单条记录处理
            if (syncPersonFromCamera(personData, sn)) {
                successCount++;
            }
        }

        return successCount;
    }

    // 支持旧方法调用（向后兼容）

    @Transactional
    public int syncPersonsFromCamera(List<Map<String, Object>> personList) {
        // 由于没有SN参数，设置为空，将导致每个人员记录没有设备ID
        log.warn("调用了不带设备SN的同步方法，人员记录将不包含设备ID");
        return syncPersonsFromCamera(personList, null);
    }

    /**
     * 从摄像头服务器同步人员信息
     *
     * @param personData 人员数据
     * @param sn         设备SN
     * @return 是否成功
     */
    @Override
    public boolean syncPersonFromCamera(Map<String, Object> personData, String sn) {
        if (personData == null || personData.isEmpty()) {
            return false;
        }

        String pid = (String) personData.get("pid");
        if (pid == null || pid.isEmpty()) {
            log.warn("从摄像头获取的人员数据缺少PID，跳过处理: {}", personData);
            return false;
        }

        // 1. 检查人员-设备关联关系是否存在
        boolean relationExists = !personDeviceRelService.checkPersonDeviceRelNotExists(pid, sn);

        // 2. 更新或插入人员信息
        PerPerson person = new PerPerson();
        person.setPid(pid);
        person.setName((String) personData.get("name"));
        person.setWorkId((String) personData.get("work_id"));
        person.setIdCardNo((String) personData.get("id_card_no"));
        person.setIcCardNo((String) personData.get("ic_card_no"));
        person.setDepartment((String) personData.get("department"));
        person.setPhone((String) personData.get("phone"));

        Object genderObj = personData.get("gender");
        if (genderObj instanceof Integer) {
            person.setGender((Integer) genderObj);
        } else if (genderObj instanceof String) {
            try {
                person.setGender(Integer.parseInt((String) genderObj));
            } catch (NumberFormatException e) {
                person.setGender(0); // 默认值
            }
        }

        // 添加对年龄字段的处理
        Object ageObj = personData.get("age");
        if (ageObj instanceof Integer) {
            person.setAge((Integer) ageObj);
        } else if (ageObj instanceof String) {
            try {
                person.setAge(Integer.parseInt((String) ageObj));
            } catch (NumberFormatException e) {
                log.warn("人员年龄解析失败，设置为null: {}", ageObj);
            }
        }
        
        // 处理人员类别
        Object categoryObj = personData.get("category");
        if (categoryObj instanceof Integer) {
            person.setCategory((Integer) categoryObj);
        } else if (categoryObj instanceof String) {
            try {
                person.setCategory(Integer.parseInt((String) categoryObj));
            } catch (NumberFormatException e) {
                log.warn("人员类别解析失败，设置为默认值4: {}", categoryObj);
                person.setCategory(4); // 默认为访客
            }
        }

        // 获取原始照片路径
        String originalPhoto = (String) personData.get("photo");
        
        // 修改照片路径，添加设备SN信息
        String modifiedPhoto = addDeviceSnToPhotoPath(originalPhoto, sn);
        person.setPhoto(modifiedPhoto);
        
        person.setDeviceId(sn); // 关联当前设备SN

        boolean updateResult;
        PerPerson existing = perPersonMapper.selectPerPersonByPid(pid);
        if (existing != null) {
            person.setId(existing.getId());
            person.setUpdateBy(SecurityUtils.getUsername());
            person.setUpdateTime(new Date());
            updateResult = perPersonMapper.updatePerPersonByPid(person) > 0;
        } else {
            person.setCreateBy(SecurityUtils.getUsername());
            person.setCreateTime(new Date());
            person.setDelFlag(0);
            updateResult = perPersonMapper.insertPerPerson(person) > 0;
        }

        // 3. 如果人员信息操作成功，且关联关系不存在，则创建关联
        if (updateResult && !relationExists) {
            PersonDeviceRel newRel = new PersonDeviceRel();
            newRel.setPersonPid(pid); // 确保这里传递的是String类型的pid
            newRel.setDeviceSn(sn);
            // 这里可以设置其他默认值，如 newRel.setSyncStatus(0L);
            personDeviceRelService.insertPersonDeviceRel(newRel);
            log.info("为人员(PID:{})和设备(SN:{})创建了新的关联记录", pid, sn);
        }
        
        return updateResult;
    }

    // 支持旧方法调用（向后兼容）

    public boolean syncPersonFromCamera(Map<String, Object> personData) {
        // 由于没有SN参数，设置为空，将导致每个人员记录没有设备ID
        log.warn("调用了不带设备SN的同步方法，人员记录将不包含设备ID");
        return syncPersonFromCamera(personData, null);
    }

    /**
     * 调用摄像头服务器删除人员信息
     *
     * @param pid 摄像头服务器中的人员ID
     * @return 是否删除成功
     */
         private boolean deletePersonFromCamera(String pid,String sn) {
         String url = cameraServerProperties.getBaseUrlBySn(sn) + "/cgi-bin/jvsweb.cgi?cmd=";
         HttpHeaders headers = new HttpHeaders();
         // 直接使用getTokenBySn获取设备访问令牌
         String accessToken = AccessTokenUtil.getTokenBySn(sn, deviceIpResolverService);
         headers.set("Cookie", "language=zh; username=admin; Access-Token=" + accessToken);

        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("uri", "/person/delete");
        requestBody.put("param", Collections.singletonMap("pid", pid));

        System.out.println("向设备发送删除请求：" + requestBody);

        try {
            ResponseEntity<Map> response = restTemplate.postForEntity(
                    url, new HttpEntity<>(requestBody, headers), Map.class);

            if (response.getStatusCode().is2xxSuccessful()) {
                Map<String, Object> responseBody = response.getBody();
                System.out.println("接收到响应：" + responseBody);

                return responseBody != null &&
                        "0".equals(responseBody.get("code").toString());
            }
        } catch (Exception e) {
            System.out.println("设备删除请求失败: " + e.getMessage());
        }
        return false;
    }

    /**
     * 将相对路径转换为完整URL
     */
    public String convertToFullUrl(String relativePath) {
        if (relativePath == null || relativePath.isEmpty()) {
            log.debug("图片路径为空，返回原路径");
            return relativePath;
        }

        // 如果已经是完整的URL，直接返回
        if (relativePath.startsWith("http")) {
            log.debug("图片已是完整URL，无需转换: {}", relativePath);
            return relativePath;
        }

        String deviceSn = null;
        String actualPath = relativePath;

        // 检查是否是新格式的路径（包含设备SN）
        // 例如：/device/PFM1254O1009701/data/facelib/8178561152496049588.jpg
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("/device/([^/]+)/(.+)");
        java.util.regex.Matcher matcher = pattern.matcher(relativePath);
        
        if (matcher.find()) {
            deviceSn = matcher.group(1);
            actualPath = matcher.group(2);
            log.debug("从路径中提取设备SN: {}, 实际路径: {}", deviceSn, actualPath);
        } else {
            log.debug("路径是旧格式，没有设备SN: {}", relativePath);
        }

        // 如果提取到设备SN，则使用设备的IP构建URL
        if (deviceSn != null && !deviceSn.isEmpty()) {
            DevDevice device = devDeviceService.selectDevDeviceBySn(deviceSn);
            
            if (device != null && device.getIp() != null && !device.getIp().isEmpty()) {
                // 构建基于设备IP的URL
                String ipPrefix = "http://" + device.getIp() + "/";
                String fullUrl;
                
                // 处理路径格式
                if (actualPath.startsWith("/")) {
                    fullUrl = ipPrefix + actualPath.substring(1);
                } else {
                    fullUrl = ipPrefix + actualPath;
                }
                
                log.debug("使用设备IP构建URL: {} -> {}", device.getIp(), fullUrl);
                return fullUrl;
            } else {
                log.warn("设备(SN:{})不存在或IP为空，使用配置的默认URL", deviceSn);
            }
        }
        
        // 对于旧格式或未能找到设备信息的情况，使用配置文件中的默认URL
        String prefix = cameraServerProperties.getPhotoPrefix();
        String fullUrl;
        
        // 处理路径格式
        if (prefix.endsWith("/") && actualPath.startsWith("/")) {
            fullUrl = prefix + actualPath.substring(1);
        } else if (!prefix.endsWith("/") && !actualPath.startsWith("/")) {
            fullUrl = prefix + "/" + actualPath;
        } else {
            fullUrl = prefix + actualPath;
        }
        
        log.debug("使用配置的默认URL前缀: {} -> {}", prefix, fullUrl);
        return fullUrl;
    }

    /**
     * 仅删除设备上的人员信息（不操作本地数据库）
     *
     * @param pids 设备人员ID数组
     * @return 成功删除数量
     */
    @Override
    public int deletePerPersonInCameraByPids(String[] pids) {
        int successCount = 0;
        for (String pid : pids) {
            PerPerson perPerson = perPersonMapper.selectPerPersonByPid(pid);
            if (deletePersonFromCamera(pid,perPerson.getDeviceId())) {
                successCount++;
            }
        }
        return successCount;
    }

    public class ServiceException extends RuntimeException {
        public ServiceException(String message) {
            super(message);
        }
    }

    @Override
    public PerPerson selectPerPersonByPid(String pid) {
        return perPersonMapper.selectPerPersonByPid(pid);
    }
}

